#ifndef SMBUS_POSTBOX_H
#define SMBUS_POSTBOX_H

#include "smbus.h"

#include <mc/core/object.h>
#include <mc/engine/base.h>
#include <mc/engine.h>

#include <cstdint>
#include <memory>
#include <string>
#include <vector>

namespace dev {

// 将协议接口并入此头，简化文件数量
class MC_API SMBusPostboxProtocol {
public:
    enum CmdStatus {
        CMD_STATUS_NULL = 0x00,
        CMD_STATUS_ERR_REQUEST = 0x01,
        CMD_STATUS_ERR_OPCODE = 0x02,
        CMD_STATUS_ERR_ARG1 = 0x03,
        CMD_STATUS_ERR_ARG2 = 0x04,
        CMD_STATUS_ERR_DATA = 0x05,
        CMD_STATUS_ERR_MISC = 0x06,
        CMD_STATUS_ERR_I2C_ACCESS = 0x07,
        CMD_STATUS_ERR_NOT_SUPPORTED = 0x08,
        CMD_STATUS_ERR_NOT_AVAILABLE = 0x09,
        CMD_STATUS_ERR_BUSY = 0x0a,
        CMD_STATUS_ERR_AGAIN = 0x0b,
        CMD_STATUS_ACCEPTED = 0x1c,
        CMD_STATUS_INACTIVE = 0x1d,
        CMD_STATUS_READY = 0x1e,
        CMD_STATUS_SUCCESS = 0x1f
    };

    enum ConvertType {
        KEEP_DIGITAL = 0,
        KEEP_ASCII = 1,
        ARRAY_TO_ASCII_BIGENDIAN = 2,
        ARRAY_TO_ASCII_LITTLEENDIAN = 3,
        KEEP_ARRAY = 4
    };

    struct RequestParams {
        std::string name;
        uint8_t opcode {0};
        uint8_t arg1 {0};
        uint8_t arg2 {0};
        uint8_t capa_dword_num {0};
        uint32_t capa_mask {0};
        bool data_out {false};
        bool ex_data_out {false};
        uint8_t data_len {0};
        ConvertType data_type {KEEP_DIGITAL};
        uint32_t data_mask {0};
    };

    virtual ~SMBusPostboxProtocol() = default;

    virtual void init(uint8_t data_reg_addr) = 0;
    virtual void registerSMBus(mc::shared_ptr<smbus> smbus_dev) = 0;
    virtual std::string sendRequest(const RequestParams& request) = 0;

    static std::shared_ptr<SMBusPostboxProtocol> create();
};

class MC_API SMBusPostbox : public mc::core::object, public SMBusPostboxProtocol {
public:
    SMBusPostbox(mc::engine::abstract_object* parent = nullptr);
    ~SMBusPostbox() override;

    void init(uint8_t data_reg_addr) override;
    void registerSMBus(mc::shared_ptr<smbus> smbus_dev) override;
    std::string sendRequest(const RequestParams& request) override;

private:
    static constexpr uint8_t NV_CMD_REG         = 0x5c; // 命令/状态寄存器
    static constexpr uint8_t NV_GPU_STATUS_MASK = 0x1f; // 状态低5位有效
    static constexpr uint8_t CMD_EXE_FLAG       = 0x80; // 触发执行的标志

    bool                writeNVGPUReg(uint32_t data, uint8_t offset);
    std::vector<uint8_t> readNVGPUReg(uint8_t offset);
    static uint32_t assembleSMBPBICommand(uint8_t opcode, uint8_t arg1, uint8_t arg2);
    static uint32_t getMaskedValue(uint32_t raw, uint32_t mask);
    CmdStatus waitAndPollStatus(int max_retry = 20, int interval_ms = 300);
    std::pair<bool, mc::mutable_dict> sendSMBusRequest(mc::mutable_dict& track_request);

private:
    uint8_t               data_reg_addr_ {0};
    mc::shared_ptr<smbus> smbus_dev_;
};

} // namespace dev

#endif // SMBUS_POSTBOX_H
